package com.ibiaoke.order.service;

import java.text.SimpleDateFormat;
import java.util.function.Predicate;

import com.ibiaoke.common.base.Page;
import com.ibiaoke.common.configs.GlobalConfigs;
import com.ibiaoke.common.configs.GlobalConfigsKey;
import com.ibiaoke.common.consts.CommonConsts;
import com.ibiaoke.common.exception.ServiceException;
import com.ibiaoke.common.response.Res;
import com.ibiaoke.common.utils.*;
import com.ibiaoke.customer.dao.CustomerDao;
import com.ibiaoke.customer.entity.Customer;
import com.ibiaoke.goods.dao.GoodsDao;
import com.ibiaoke.goods.entity.Goods;
import com.ibiaoke.marketing.consts.CouponReceiveConsts;
import com.ibiaoke.marketing.dao.CouponReceiveDao;
import com.ibiaoke.marketing.entity.CouponReceive;
import com.ibiaoke.marketing.service.CouponReceiveService;
import com.ibiaoke.order.consts.OrderStatusConst;
import com.ibiaoke.order.dao.*;
import com.ibiaoke.order.entity.*;
import com.ibiaoke.order.entity.so.OrderSO;
import com.ibiaoke.order.entity.so.PtOrderSO;
import com.ibiaoke.order.entity.so.SubmitOrderSO;
import com.ibiaoke.order.entity.vo.DateAnalysisVO;
import com.ibiaoke.order.entity.vo.OrderGoodsVO;
import com.ibiaoke.order.entity.vo.OrderVO;
import com.ibiaoke.system.dao.ShopDao;
import com.ibiaoke.system.entity.Shop;
import com.ibiaoke.system.entity.dto.DeliverInfoDTO;
import com.ibiaoke.system.service.ShopService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;

import static com.ibiaoke.common.utils.StringUtils.nullToEmpty;
import static java.util.stream.Collectors.toList;

/**
 * Created by huhaichao on 2017/6/8.
 */
@Service
public class OrderServiceImpl implements OrderService {

    private Logger logger = Logger.getLogger(this.getClass().getName());

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private PtOrderDao ptOrderDao;
    @Autowired
    private OrderGoodsDao orderGoodsDao;
    @Autowired
    private GoodsDao goodsDao;

    @Autowired
    private ShoppingCartDao shoppingCartDao;

    @Autowired
    private ShoppingCartService shoppingCartService;

    @Autowired
    private CouponReceiveService couponReceiveService;
    @Autowired
    private OrderAddressDao orderAddressDao;
    @Autowired
    private ShopService shopService;

    @Autowired
    private GoodsRushService goodsRushService;
    @Autowired
    private CouponReceiveDao couponReceiveDao;
    @Autowired
    private ShopDao shopDao;
    @Autowired
    private CustomerDao customerDao;

    /**
     * 查询订单列表
     *
     * @param orderSO
     * @param page
     * @return
     */
    @Override
    public List<OrderVO> listOrder(OrderSO orderSO, Page page) {
        if(orderSO.getMobile() != null && !"".equals(orderSO.getMobile())){
            Customer c  = customerDao.getByMobile(orderSO.getMobile());
            if(c==null){
                throw new ServiceException("此用户不存在，请核实");
            }else{
                orderSO.setUserId(c.getCustomerId());
            }
        }
        List<Order> orders = orderDao.listOrder(orderSO, page);
        return fillOrderListWithGoods(orders);
    }

    @Override
    public List<OrderVO> listOpenOrder(OrderSO orderSO, Page page) {
        List<Order> orders = orderDao.listOrder(orderSO, page);
        Date time = DateUtils.add(Calendar.HOUR_OF_DAY, -1);
        Predicate<Order> orderPredicate = order -> !((order.getOrderStatus() == OrderStatusConst.UNPAID && order.getCreateTime().before(time)));
        orders = orders.stream().filter(orderPredicate).collect(toList());
        return fillOrderListWithGoods(orders);
    }

    /**
     * 获取订单详情
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderVO getOrder(Integer orderId) {
        AssertUtils.notNull(orderId,"订单号不能为空");
        Order order = orderDao.selectByPrimaryKey(orderId);
        ValidateUtils.notNull(order, "订单不存在");
        List<OrderGoods> orderGoods = orderGoodsDao.listOrderGoods(orderId);
        return fillOrderWithGoods(orderGoods, order);
    }


    private List<OrderVO> fillOrderListWithGoods(List<Order> orders) {
        if (orders == null) {
            return null;
        }
        List<Integer> orderIds = orders.stream().map(Order::getOrderId).collect(toList());
        //查询所有商品
        List<OrderGoods> orderGoodsList = orderGoodsDao.listOrderGoods(orderIds);
        List<OrderVO> orderVOS = orders.stream().map(order -> fillOrderWithGoods(orderGoodsList, order)).collect(toList());
        return orderVOS;
    }

    private OrderVO fillOrderWithGoods(List<OrderGoods> orderGoodsList, Order order) {
        List<OrderGoodsVO> orderGoodsVOList = orderGoodsList.stream()
                .filter(orderGoods -> Objects.equals(orderGoods.getOrderId(), order.getOrderId()))
                .map(orderGoods -> {
                    OrderGoodsVO orderGoodsVO = new OrderGoodsVO();
                    BeanUtils.copyProperties(orderGoods, orderGoodsVO);
                    return orderGoodsVO;
                }).collect(toList());

        List<Integer> goodsIds = orderGoodsVOList.stream().map(OrderGoodsVO::getGoodsId).collect(toList());
        List<Goods> goodsList = goodsDao.listByIds(goodsIds, order.getShopId());

        orderGoodsVOList.forEach(orderGoodsVO -> {
            goodsList.forEach(goods -> {
                if (Objects.equals(orderGoodsVO.getGoodsId(), goods.getGoodsId())) {
                    orderGoodsVO.setGoods(goods);
                }
            });
        });

        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(order, orderVO);
        orderVO.setOrderGoodsList(orderGoodsVOList);
        return orderVO;
    }

    /**
     * 发货
     *
     * @param orderId
     */
    @Override
    public Integer deliverOrder(Integer orderId) {
        if (orderId == null) {
            throw new ServiceException("订单不存在");
        }
        Order order = orderDao.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }
        if (order.getOrderStatus() != OrderStatusConst.PAID) {
            throw new ServiceException("非待发货订单无法发货");
        }

        return orderDao.updateOrderStatus(orderId, OrderStatusConst.DELIVERED);
    }

    private Function<ShoppingCart, OrderGoods> cartToOrderGoodsFunction = shoppingCart -> {

        Goods goods = shoppingCart.getGoods();

        OrderGoods og = new OrderGoods();
        og.setGoodsId(shoppingCart.getGoodsId());
        og.setGoodsName(goods.getName());
        og.setGoodsImage(goods.getImage());
        og.setGoodsPrice(goods.getPrice());
        og.setGoodsSpec(goods.getSpec());

        og.setNum(shoppingCart.getNum());
        og.setDelStatus(CommonConsts.NO);
        og.setUpdateTime(new Date());
        og.setCreateTime(new Date());
        return og;
    };

    /**
     * 购物车下单
     *
     * @param submitOrderSO
     */
    @Override
    @Transactional
    public Integer submitShoppingCartOrder(SubmitOrderSO submitOrderSO) {

        AssertUtils.notBlank(submitOrderSO.getShoppingCartIds(), "请选择商品");
        AssertUtils.notNull(submitOrderSO.getUserId(), "请先登录");
        if ("1".equals(submitOrderSO.getDeliveryType())) {
            String[] shoppingCartIds = submitOrderSO.getShoppingCartIds().split(CommonConsts.SPLIT_CHAR);
            List<Integer> shoppingCartIdList = Arrays.asList(shoppingCartIds).stream().map(Integer::parseInt).collect(toList());
            List<ShoppingCart> shoppingCarts = shoppingCartDao.listShoppingCart(shoppingCartIdList);
            //OrderAddress address = orderAddressDao.selectByPrimaryKey(submitOrderSO.getAddressId());
            //店铺限制
            //String info = shopService.validateDistanceAndOpenTime(address.getLongitude(), address.getLatitude());
            //AssertUtils.requireTrue(StringUtils.isEmpty(info), info);
            //Shop shop = shopService.getNearestShop(address.getLongitude(), address.getLatitude());
            shoppingCartService.fillGoods(shoppingCarts, submitOrderSO.getShopId());
            validateShoppingCarts(shoppingCarts);
            //限时抢购
            shoppingCarts.forEach(shoppingCart -> goodsRushService.validateCount2(shoppingCart.getGoods(), shoppingCart.getNum(), submitOrderSO.getUserId(), true));
            BigDecimal productPrice = shoppingCarts.stream().map(shoppingCart -> shoppingCart.getGoods().getPrice().multiply(new BigDecimal(shoppingCart.getNum())))
                    .reduce(BigDecimal.ZERO, (BigDecimal::add));
            //DeliverInfoDTO deliverInfoDTO = shopService.getDeliveryInfo(address.getLongitude(), address.getLatitude(), productPrice);
            //BigDecimal expressPrice = deliverInfoDTO.getDeliveryPrice();
            //BigDecimal oldPrice = productPrice.add(expressPrice);
            //BigDecimal orderPrice = productPrice.add(expressPrice);
            AssertUtils.requireTrue(productPrice.compareTo(new BigDecimal(15)) >= 0, "订单金额不满15元，无法下单");
            Order order = new Order();
            order.setShopId(submitOrderSO.getShopId());
            order.setOrderCode(generateOrderNo());
            order.setOrderStatus(OrderStatusConst.UNPAID);
            order.setUserId(submitOrderSO.getUserId());
            order.setOrderPrice(productPrice);
            order.setOrderOldPrice(productPrice);
            order.setExpressPrice(new BigDecimal(0));
            BigDecimal maxPrice = null;
            if (submitOrderSO.getCouponReceiveId() != null) {
                CouponReceive couponReceive = couponReceiveDao.selectByPrimaryKey(submitOrderSO.getCouponReceiveId());
                if (Objects.equals(couponReceive.getUseType(), CouponReceiveConsts.USE_TYPE_GOODS)) {
                    maxPrice = shoppingCarts.parallelStream()
                            .filter(shoppingCart -> Objects.equals(shoppingCart.getGoodsId(), couponReceive.getCanUseId()))
                            .map(shoppingCart -> shoppingCart.getGoods().getPrice().multiply(BigDecimal.valueOf(shoppingCart.getNum())))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    AssertUtils.requireTrue(maxPrice.compareTo(BigDecimal.ZERO) > 0, "此优惠券不能用于此商品");
                }
            }
            useCoupon(order, maxPrice, submitOrderSO.getCouponReceiveId());
            //order.setDeliveryLocationId(address.getAddressId());
            Shop shop = shopDao.getShopByShopId(submitOrderSO.getShopId());
            if (shop != null) {
                order.setDeliveryAddress(shop.getShopName());
            }
            order.setDeliveryType(1);
            //order.setContactMobile(address.getContactPhone());
            //order.setContactPersion(address.getContactName());
            //order.setLongitude(address.getLongitude());
            //order.setLatitude(address.getLatitude());
            order.setRemarke(submitOrderSO.getRemarke());
            //order.setDistance(LocationUtils.getDistance(address.getLongitude(), address.getLatitude(), shop.getDesLongitude(), shop.getDesLatitude()));
            order.setDelStatus((byte) CommonConsts.NO);
            order.setSource(submitOrderSO.getSource());
            order.setUpdateTime(new Date());
            order.setCreateTime(new Date());
            orderDao.insertSelective(order);
            order = orderDao.getOrderByOrderCode(order.getOrderCode());
            List<OrderGoods> orderGoodsList = shoppingCarts.stream().map(cartToOrderGoodsFunction).collect(toList());
            Integer orderId = order.getOrderId();
            orderGoodsList.forEach(orderGoods -> orderGoods.setOrderId(orderId));
            orderGoodsDao.batchInsert(orderGoodsList);
            shoppingCartDao.batchDeleteShoppingCart(shoppingCartIdList, submitOrderSO.getUserId());
            return order.getOrderId();
        }

        String[] shoppingCartIds = submitOrderSO.getShoppingCartIds().split(CommonConsts.SPLIT_CHAR);

        List<Integer> shoppingCartIdList = Arrays.asList(shoppingCartIds).stream().map(Integer::parseInt).collect(toList());


        List<ShoppingCart> shoppingCarts = shoppingCartDao.listShoppingCart(shoppingCartIdList);
        OrderAddress address = orderAddressDao.selectByPrimaryKey(submitOrderSO.getAddressId());
        //店铺限制
        String info = shopService.validateDistanceAndOpenTime(address.getLongitude(), address.getLatitude());
        AssertUtils.requireTrue(StringUtils.isEmpty(info), info);
        Shop shop = shopService.getNearestShop(address.getLongitude(), address.getLatitude());
        shoppingCartService.fillGoods(shoppingCarts, shop.getShopId());
        validateShoppingCarts(shoppingCarts);
        //限时抢购
        shoppingCarts.forEach(shoppingCart -> goodsRushService.validateCount2(shoppingCart.getGoods(), shoppingCart.getNum(), submitOrderSO.getUserId(), true));

        BigDecimal productPrice = shoppingCarts.stream().map(shoppingCart -> shoppingCart.getGoods().getPrice().multiply(new BigDecimal(shoppingCart.getNum())))
                .reduce(BigDecimal.ZERO, (BigDecimal::add));


        DeliverInfoDTO deliverInfoDTO = shopService.getDeliveryInfo(address.getLongitude(), address.getLatitude(), productPrice);
        BigDecimal expressPrice = deliverInfoDTO.getDeliveryPrice();
        BigDecimal oldPrice = productPrice.add(expressPrice);
        BigDecimal orderPrice = productPrice.add(expressPrice);
        AssertUtils.requireTrue(orderPrice.compareTo(new BigDecimal(15)) >= 0, "订单金额不满15元，无法下单");
        Order order = new Order();
        order.setShopId(deliverInfoDTO.getShopId());
        order.setOrderCode(generateOrderNo());
        order.setOrderStatus(OrderStatusConst.UNPAID);
        order.setUserId(submitOrderSO.getUserId());

        order.setOrderPrice(orderPrice);
        order.setOrderOldPrice(oldPrice);
        order.setExpressPrice(expressPrice);

        BigDecimal maxPrice = null;
        if (submitOrderSO.getCouponReceiveId() != null) {
            CouponReceive couponReceive = couponReceiveDao.selectByPrimaryKey(submitOrderSO.getCouponReceiveId());
            if (Objects.equals(couponReceive.getUseType(), CouponReceiveConsts.USE_TYPE_GOODS)) {
                maxPrice = shoppingCarts.parallelStream()
                        .filter(shoppingCart -> Objects.equals(shoppingCart.getGoodsId(), couponReceive.getCanUseId()))
                        .map(shoppingCart -> shoppingCart.getGoods().getPrice().multiply(BigDecimal.valueOf(shoppingCart.getNum())))
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                AssertUtils.requireTrue(maxPrice.compareTo(BigDecimal.ZERO) > 0, "此优惠券不能用于此商品");
            }
        }
        useCoupon(order, maxPrice, submitOrderSO.getCouponReceiveId());

        order.setDeliveryLocationId(address.getAddressId());
        order.setDeliveryAddress(address.toDetailAddress());
        order.setContactMobile(address.getContactPhone());
        order.setContactPersion(address.getContactName());
        order.setLongitude(address.getLongitude());
        order.setLatitude(address.getLatitude());
        order.setRemarke(submitOrderSO.getRemarke());
        order.setDistance(LocationUtils.getDistance(address.getLongitude(), address.getLatitude(), shop.getDesLongitude(), shop.getDesLatitude()));
        order.setDelStatus((byte) CommonConsts.NO);
        order.setSource(submitOrderSO.getSource());
        order.setUpdateTime(new Date());
        order.setCreateTime(new Date());

        orderDao.insertSelective(order);
        order = orderDao.getOrderByOrderCode(order.getOrderCode());

        List<OrderGoods> orderGoodsList = shoppingCarts.stream().map(cartToOrderGoodsFunction).collect(toList());
        Integer orderId = order.getOrderId();
        orderGoodsList.forEach(orderGoods -> orderGoods.setOrderId(orderId));
        orderGoodsDao.batchInsert(orderGoodsList);
        shoppingCartDao.batchDeleteShoppingCart(shoppingCartIdList, submitOrderSO.getUserId());
        return order.getOrderId();
    }


    @Override
    @Transactional
    public Integer submitGoodsOrder(SubmitOrderSO submitOrderSO) {
        AssertUtils.notNull(submitOrderSO.getGoodsId(), "请选择商品");
        AssertUtils.notNull(submitOrderSO.getUserId(), "请先登录");
        if ("1".equals(submitOrderSO.getDeliveryType())) {
            Goods goods = goodsDao.getGoods(submitOrderSO.getGoodsId(), submitOrderSO.getShopId());

            //限时购
            goodsRushService.validateCount2(goods, 1, submitOrderSO.getUserId(), true);
            //校验商品
            validateGoods(goods);
            //验证商品的库存量
            AssertUtils.requireTrue(goods.getStockNum() > 0, "库存量已经不足");

            Order order = new Order();
            order.setShopId(submitOrderSO.getShopId());
            order.setOrderCode(generateOrderNo());
            order.setOrderStatus(OrderStatusConst.UNPAID);
            order.setUserId(submitOrderSO.getUserId());

            order.setOrderPrice(goods.getPrice());
            order.setOrderOldPrice(goods.getPrice());
            order.setExpressPrice(new BigDecimal(0));

            BigDecimal maxPrice = null;
            if (submitOrderSO.getCouponReceiveId() != null) {
                CouponReceive couponReceive = couponReceiveDao.selectByPrimaryKey(submitOrderSO.getCouponReceiveId());
                //判断优惠券的使用类型
                if (couponReceive.getUseType() != null && couponReceive.getUseType() == 1) {
                    AssertUtils.requireEquals(couponReceive.getCanUseId(), goods.getGoodsId(), "此优惠券不能用于此商品");
                    maxPrice = goods.getPrice();
                }
            }
            useCoupon(order, maxPrice, submitOrderSO.getCouponReceiveId());

            //order.setDeliveryLocationId(address.getAddressId());
            Shop shop = shopDao.getShopByShopId(submitOrderSO.getShopId());
            if (shop != null) {
                order.setDeliveryAddress(shop.getShopName());
            }
            order.setDeliveryType(1);
            //order.setContactMobile(address.getContactPhone());
            //order.setContactPersion(address.getContactName());
            //order.setLongitude(address.getLongitude());
            //order.setLatitude(address.getLatitude());
            order.setRemarke(submitOrderSO.getRemarke());
            //order.setDistance(LocationUtils.getDistance(address.getLongitude(), address.getLatitude(), shop.getDesLongitude(), shop.getDesLatitude()));
            order.setDelStatus((byte) CommonConsts.NO);
            order.setSource(submitOrderSO.getSource());
            order.setUpdateTime(new Date());
            order.setCreateTime(new Date());

            orderDao.insertSelective(order);
            order = orderDao.getOrderByOrderCode(order.getOrderCode());

            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setOrderId(order.getOrderId());
            orderGoods.setGoodsId(goods.getGoodsId());
            orderGoods.setNum(1);
            orderGoods.setDelStatus(0);
            orderGoodsDao.insertSelective(orderGoods);
            return order.getOrderId();
        }
        OrderAddress address = orderAddressDao.selectByPrimaryKey(submitOrderSO.getAddressId());
        //店铺限制
        String info = shopService.validateDistanceAndOpenTime(address.getLongitude(), address.getLatitude());
        AssertUtils.requireTrue(StringUtils.isEmpty(info), info);

        Shop shop = shopService.getNearestShop(address.getLongitude(), address.getLatitude());
        Goods goods = goodsDao.getGoods(submitOrderSO.getGoodsId(), shop.getShopId());

        validateGoods(goods);
        //验证商品的库存量
        AssertUtils.requireTrue(goods.getStockNum() > 0, "库存量已经不足");


        //限时购
        goodsRushService.validateCount2(goods, 1, submitOrderSO.getUserId(), true);

        BigDecimal productPrice = goods.getPrice();
        //获取运费金额
        DeliverInfoDTO deliverInfoDTO = shopService.getDeliveryInfo(address.getLongitude(), address.getLatitude(), productPrice);
        BigDecimal expressPrice = deliverInfoDTO.getDeliveryPrice();

        BigDecimal oldPrice = productPrice.add(expressPrice);
        BigDecimal orderPrice = productPrice.add(expressPrice);
        Order order = new Order();
        order.setShopId(deliverInfoDTO.getShopId());
        order.setOrderCode(generateOrderNo());
        order.setOrderStatus(OrderStatusConst.UNPAID);
        order.setUserId(submitOrderSO.getUserId());

        order.setOrderPrice(orderPrice);
        order.setOrderOldPrice(oldPrice);
        order.setExpressPrice(expressPrice);

        BigDecimal maxPrice = null;
        if (submitOrderSO.getCouponReceiveId() != null) {
            CouponReceive couponReceive = couponReceiveDao.selectByPrimaryKey(submitOrderSO.getCouponReceiveId());
            //判断优惠券的使用类型
            if (couponReceive.getUseType() != null && couponReceive.getUseType() == 1) {
                AssertUtils.requireEquals(couponReceive.getCanUseId(), goods.getGoodsId(), "此优惠券不能用于此商品");
                maxPrice = goods.getPrice();
            }
        }
        useCoupon(order, maxPrice, submitOrderSO.getCouponReceiveId());

        order.setDeliveryLocationId(address.getAddressId());
        order.setDeliveryAddress(address.toDetailAddress());
        order.setContactMobile(address.getContactPhone());
        order.setContactPersion(address.getContactName());
        order.setLongitude(address.getLongitude());
        order.setLatitude(address.getLatitude());
        order.setRemarke(submitOrderSO.getRemarke());
        order.setDistance(LocationUtils.getDistance(address.getLongitude(), address.getLatitude(), shop.getDesLongitude(), shop.getDesLatitude()));
        order.setDelStatus((byte) CommonConsts.NO);
        order.setSource(submitOrderSO.getSource());
        order.setUpdateTime(new Date());
        order.setCreateTime(new Date());

        orderDao.insertSelective(order);
        order = orderDao.getOrderByOrderCode(order.getOrderCode());

        OrderGoods orderGoods = new OrderGoods();
        orderGoods.setOrderId(order.getOrderId());
        orderGoods.setGoodsId(goods.getGoodsId());
        orderGoods.setNum(1);
        orderGoods.setDelStatus(0);
        orderGoodsDao.insertSelective(orderGoods);
        return order.getOrderId();
    }

    @Override
    public Long getOrderNum(Integer customerId, int orderStatus) {
        AssertUtils.notNull(customerId, "客户Id不能为空");
        AssertUtils.notNull(orderStatus, "订单状态不能为空");

        return orderDao.countOrder(customerId, orderStatus);
    }

    @Override
    public Integer cancelOrder(Integer customerId, Integer orderId) {
        AssertUtils.notNull(customerId, "客户Id不能为空");
        AssertUtils.notNull(orderId, "订单Id不能为空");
        Order order = orderDao.selectByPrimaryKey(orderId);
        AssertUtils.requireEquals(customerId, order.getUserId(), "不要调皮哦");
        AssertUtils.requireTrue(order.getOrderStatus() == OrderStatusConst.UNPAID, "已支付订单不能取消");
        if (order.getCouponReceiveId() != null) {
            releaseCoupon(orderId, order.getCouponReceiveId());
        }
        return orderDao.cancelOrder(customerId, orderId);
    }

    private void releaseCoupon(Integer orderId, Integer couponReceiveId) {
        couponReceiveService.releaseCoupon(couponReceiveId);
    }

    @Override
    public int confirmOrder(Integer customerId, Integer orderId) {
        AssertUtils.notNull(customerId, "客户Id不能为空");
        AssertUtils.notNull(orderId, "订单Id不能为空");
        int count = orderDao.confirmOrder(customerId, orderId);
        AssertUtils.requireTrue(count > 0, "确认收货失败");
        return count;
    }

    @Override
    public String generateOrderNo() {
        String dateNo = DateUtils.formatOrderNoDate(new Date());
        return dateNo + RandomUtils.generatorOrderNo();
    }

    private boolean validateShoppingCarts(List<ShoppingCart> shoppingCarts) {
        shoppingCarts.forEach(shoppingCart -> {
            Goods goods = shoppingCart.getGoods();
            validateGoods(goods);
        });
        return true;
    }

    private boolean validateGoods(Goods goods) {
        AssertUtils.notNull(goods, "商品已下架");
        AssertUtils.requireTrue(goods.getStockNum() > 0, "该店库存不足");
        AssertUtils.requireTrue(goods.getDelStatus() == CommonConsts.NO, "商品" + goods.getName() + "已下架");
        AssertUtils.requireTrue(goods.getStatus() == 1, "商品" + goods.getName() + "已下架");
        return true;
    }

    /**
     * 获取当日的对应门店线上订单数据分析
     *
     * @param orderSO
     * @param page
     */
    @Override
    public HashMap<String, DateAnalysisVO> getTodayOrderData(OrderSO orderSO, PtOrderSO ptOrderSO, Page page) {
        Date startTime = DateUtils.theDayBegin(0);
        Date endTime = DateUtils.theDayBegin(1);

        orderSO.setBeginTime(startTime);
        orderSO.setEndTime(endTime);

        ptOrderSO.setBeginTime(startTime);
        ptOrderSO.setEndTime(endTime);

        return getOrderAnalysis(orderSO, ptOrderSO, page);
    }

    /**
     * 根据传入时间来查询门店的历史销售详情
     *
     * @param orderSO
     * @param page
     */
    @Override
    public HashMap<String, DateAnalysisVO> getOrderAnalysis(OrderSO orderSO, PtOrderSO ptOrderSO, Page page) {
        Res res = Res.create();
        orderSO.setDateAnalysis(true);
        ptOrderSO.setDateAnalysis(true);
        List<Order> list = orderDao.listOrder(orderSO, page);
        List<Order> listByExpress = new ArrayList<>();
        List<Order> listByOneSelf = new ArrayList<>();
        List<PtOrder> ptOrders = ptOrderDao.listOrder(ptOrderSO, page);
        //总的
        DateAnalysisVO dateAnalysisVOAll = getDateAnalysisVO(list);

        for (Order order : list) {
            if (order.getDeliveryType() == OrderStatusConst.DELIVERY_TYPE_EXPRESS) {
                listByExpress.add(order);
            }
            if (order.getDeliveryType() == OrderStatusConst.DELIVERY_TYPE_ARIIVE) {
                listByOneSelf.add(order);
            }
        }
        //线上
        DateAnalysisVO dateAnalysisVOExpress = getDateAnalysisVO(listByExpress);
        //快捷支付
        DateAnalysisVO dateAnalysisVOOneSelf = getDateAnalysisVO(listByOneSelf);
        //拼团
        DateAnalysisVO dateAnalysisVOPt = getPtDateAnalusisVo(ptOrders);

        HashMap map = new HashMap<String, DateAnalysisVO>();
        map.put("dateAnalysisVOAll", dateAnalysisVOAll);
        map.put("dateAnalysisVOExpress", dateAnalysisVOExpress);
        map.put("dateAnalysisVOOneSelf", dateAnalysisVOOneSelf);
        map.put("dateAnalysisVOPt", dateAnalysisVOPt);
        return map;
    }

    @Override
    public int payOrder(String orderNo, int payType) {
        Order order = orderDao.getOrderByOrderCode(orderNo);
        if (order == null || !Objects.equals(order.getOrderStatus(), OrderStatusConst.UNPAID)) {
            return 0;
        }
        int row = orderDao.payOrder(order.getOrderId(), payType);
        if (row > 0) {
            sendOrderMessage(order);
        }
        return row;
    }


    private DateAnalysisVO getDateAnalysisVO(List<Order> orders) {
        DateAnalysisVO dateAnalysisVO = new DateAnalysisVO();
        if (CollectionUtils.isNotEmpty(orders)) {
            BigDecimal totalPrice = orders.stream().map(Order::getOrderPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            dateAnalysisVO.setTotalPrice(totalPrice);
            dateAnalysisVO.setTradeCount(orders.size());
            //BigDecimal的除法,2位精确度，HALF_EVEN舍入法
            dateAnalysisVO.setCustomerPrice(totalPrice.divide(new BigDecimal(orders.size()), 2, RoundingMode.HALF_EVEN));
        }
        return dateAnalysisVO;
    }

    private DateAnalysisVO getPtDateAnalusisVo(List<PtOrder> ptOrders) {
        DateAnalysisVO dateAnalysisVO = new DateAnalysisVO();
        if (CollectionUtils.isNotEmpty(ptOrders)) {
            BigDecimal totalPrice = ptOrders.stream().map(PtOrder::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            dateAnalysisVO.setTotalPrice(totalPrice);
            dateAnalysisVO.setTradeCount(ptOrders.size());
            //BigDecimal的除法,2位精确度，HALF_EVEN舍入法
            dateAnalysisVO.setCustomerPrice(totalPrice.divide(new BigDecimal(ptOrders.size()), 2, RoundingMode.HALF_EVEN));
        }
        return dateAnalysisVO;
    }

    @Override
    public Integer saveOrder(Order order) {
        AssertUtils.notBlank(order.getOrderCode(), "订单编号不能为空");
        AssertUtils.notNull(order.getUserId(), "用户编号不能为空");
        return orderDao.insertSelective(order);
    }


    @Override
    public Order getOrderInfoByCode(String orderNo) {
        AssertUtils.notBlank(orderNo, "订单编号不能为空");
        return orderDao.getOrderByOrderCode(orderNo);
    }


    @Override
    public void sendOrderMessage(Order order) {
        Shop nearestShop = null;
        if (order.getShopId() != null && order.getShopId() != 0) {
            nearestShop = shopService.getShop(order.getShopId());
        }
        if (nearestShop == null) {
            nearestShop = shopService.getNearestShop(order.getLongitude(), order.getLatitude());
            order.setShopId(nearestShop.getShopId());
            orderDao.updateOrderShop(order.getOrderId(), nearestShop.getShopId());
        }
        String template = "JSM40225-0004";
        StringBuilder content = getOrderSmsContent(order, nearestShop);
        if (content.length() >= 300) {
            content = getOrderSmsUrlContent(order, nearestShop);
            template = GlobalConfigs.getConfigure(GlobalConfigsKey.SMS_TEMPLATE_ORDER_URL);
        }
        SmsUtil.sendOrderMsgWithTemp(nearestShop.getShopMobile(), template, content.toString());
    }

    /**
     * 使用优惠券，需要保证订单金额、运费不能为空
     *
     * @param order
     * @param maxPrice
     * @param couponReceiveId @return
     */
    @Override
    public Order useCoupon(Order order, BigDecimal maxPrice, Integer couponReceiveId) {
        AssertUtils.notNull(order, "订单不存在");
        AssertUtils.notNull(order.getOrderPrice(), "优惠券使用错误，订单金额为空");
        AssertUtils.notNull(order.getExpressPrice(), "优惠券使用错误，运费为空");
        if (couponReceiveId != null) {
            BigDecimal orderPrice = order.getOrderPrice();
            BigDecimal goodsPrice = orderPrice.subtract(order.getExpressPrice());
            CouponReceive couponReceive = couponReceiveService.useCouponReceive(couponReceiveId, goodsPrice);
            BigDecimal couponPrice = couponReceive.getCouponPrice();
            if (maxPrice != null && couponPrice.compareTo(maxPrice) > 0) {
                couponPrice = maxPrice;
            }
            orderPrice = orderPrice.subtract(couponPrice);
            if (orderPrice.compareTo(new BigDecimal("0.01")) < 0) {
                orderPrice = new BigDecimal("0.01");
            }

            order.setCouponPrice(couponPrice);
            order.setOrderPrice(orderPrice);
            order.setCouponReceiveId(couponReceiveId);
        }
        return order;
    }

    @Override
    public String changeOrderNo(Integer orderId) {
        String orderNo = generateOrderNo();
        orderDao.changeOrderNo(orderId, orderNo);
        return orderNo;
    }

    public StringBuilder getOrderSmsContent(Order orderInfo, Shop nearestShop) {
        // @param content @1@=浦口店,@2@=201708286783,@3@=香蕉(箱*2),@4@=陈诚,@5@=13888888888,@6@=江苏省南京市建邺区
        StringBuilder content = new StringBuilder();

        content.append("@1@=" + nearestShop.getShopName() + ",");
        content.append("@2@=" + orderInfo.getOrderCode() + ",");

        List<OrderGoods> relGoodsList = orderGoodsDao.listOrderGoods(orderInfo.getOrderId());
        List<Integer> goodsIds = relGoodsList.stream().map(OrderGoods::getGoodsId).collect(toList());
        List<Goods> goodsList = goodsDao.listByIds(goodsIds, nearestShop.getShopId());
        Map<Integer, Goods> goodsMap = new HashMap();
        for (Goods goods : goodsList) {
            goodsMap.put(goods.getGoodsId(), goods);
        }

        if (CollectionUtils.isNotEmpty(relGoodsList)) {
            StringBuilder goodsInfoContent = new StringBuilder();
            for (OrderGoods relGoods : relGoodsList) {
                Goods goods = goodsMap.get(relGoods.getGoodsId());
                if (goods != null) {
                    goodsInfoContent.append(goods.getName() + "(" + goods.getSpec() + goods.getPrice() + " * " + relGoods.getNum() + ")\n");
                }
            }
            content.append("@3@=" + goodsInfoContent.toString().replace(",", "") + " ,");
        } else {
            content.append("@3@=" + " ,");
        }

        content.append("@4@=" + nullToEmpty(orderInfo.getContactPersion()) + ",");
        content.append("@5@=" + nullToEmpty(orderInfo.getContactMobile()) + ",");
        content.append("@6@=" + nullToEmpty(orderInfo.getDeliveryAddress()));

        String deliveryType = orderInfo.getDeliveryType().intValue() == 1 ? "自提" : "快递";
        content.append("\n[配送类型:]" + deliveryType);

        content.append("\n[实付金额(不含邮费):]" + orderInfo.getOrderPrice().subtract(orderInfo.getExpressPrice()) + "元");
        content.append("\n[优惠券抵扣金额:]" + orderInfo.getCouponPrice() + "元");
        return content;
    }

    public StringBuilder getOrderSmsUrlContent(Order orderInfo, Shop nearestShop) {
        // @param content @1@=浦口店,@2@=201708286783,@3@=香蕉(箱*2),@4@=陈诚,@5@=13888888888,@6@=江苏省南京市建邺区
        StringBuilder content = new StringBuilder();

        content.append("@1@=" + nearestShop.getShopName() + ",");
        content.append("@2@=" + orderInfo.getOrderCode() + ",");

        String code = DesUtils.encrypt(String.valueOf(orderInfo.getOrderId()));
        content.append("@3@=" + code + "\n" + SmsUtil.SMS_WITH_URL_FLAG + " ,");

        content.append("@4@=" + nullToEmpty(orderInfo.getContactPersion()) + ",");
        content.append("@5@=" + nullToEmpty(orderInfo.getContactMobile()) + ",");
        content.append("@6@=" + nullToEmpty(orderInfo.getDeliveryAddress()));

        String deliveryType = orderInfo.getDeliveryType().intValue() == 1 ? "自提" : "快递";
        content.append("\n[配送类型:]" + deliveryType);

        content.append("\n[实付金额(不含邮费):]" + orderInfo.getOrderPrice().subtract(orderInfo.getExpressPrice()) + "元");
        content.append("\n[优惠券抵扣金额:]" + orderInfo.getCouponPrice() + "元");
        return content;
    }

    /**
     * 支付超过7天订单自动确认收货
     *
     * @return
     */
    @Override
    public int autoConfirmOrder() {
        Date time = DateUtils.add(Calendar.DAY_OF_MONTH, -7);
        //logger.info("自动确认收货开始执行");
        return orderDao.confirmOrder(time);
    }

    /**
     * 下单超过1个小时没有付款的，自动取消订单
     *
     * @return
     */
    @Override
    public void autoCancelOrder() {
        Date time = DateUtils.add(Calendar.HOUR_OF_DAY, -2);
        logger.info("自动取消订单执行中");
        List<Order> orders = orderDao.listCancelOrder(time);
        if (orders.size() <= 0) {
            return;
        }
        int count = orderDao.cancelOrder(time);
        if (count <= 0) {
            return;
        }
        List<Integer> couponReceiveIds = orders.stream().filter(order -> order.getCouponReceiveId() != null)
                .map(Order::getCouponReceiveId).collect(toList());
        if (CollectionUtils.isNotEmpty(couponReceiveIds)) {
            couponReceiveDao.releaseCoupon(couponReceiveIds);
        }
    }

    @Override
    public List<Order> listShopOrder(Integer shopId) {
//        AssertUtils.notBlank(mobile,"手机号码不能为空");
//        Shop shop = shopService.getShop(mobile);
//        AssertUtils.notNull(shop.getShopId(),"该手机号码未绑定店铺");
        AssertUtils.notNull(shopId, "该店铺Id不存在");
        Date begin = DateUtils.theDayBegin(0);
        Date end = DateUtils.theDayBegin(1);

        List<Order> orderList = orderDao.listShopOrder(shopId, begin, end);
        return orderList;
    }

    /**
     * 退款时，更改订单状态
     *
     * @param orderId
     * @return
     */
    @Override
    @Transactional
    public Order updateOrderStatus(Integer orderId) {
        int count = orderDao.updateOrderStatus(orderId, 4);
        OrderExample example = new OrderExample();
        example.createCriteria().andOrderIdEqualTo(orderId);
        Order order = orderDao.selectByPrimaryKey(orderId);
        return order;
    }

    @Override
    public String aggregate(Integer serviceNum, Date startTime, Date endTime) {
        List<Order> orderList = orderDao.aggregate(serviceNum, startTime, endTime);
        List<PtOrder> ptOrderList = ptOrderDao.aggregate(serviceNum, startTime, endTime);
        //订单总价
        BigDecimal totalPrice = orderList.stream().map(Order::getOrderPrice).reduce(BigDecimal.ZERO, BigDecimal::add);

        //拼团总价
        BigDecimal PttotalPrice = ptOrderList.stream().map(PtOrder::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);

        return totalPrice.add(PttotalPrice).toString();
    }

}
